﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml.Linq;
using SqlToMongoCore;

namespace SqlToMongo
{
    public partial class MainWindow : Form
    {
        public static class ColumnMapping
        {
            public const int IsSelected = 0;
            public const int SQLTable = 1;
            public const int PrimaryKeyColumn = 2;
            public const int MongoCollection = 3;
            public const int PageSize = 4;
            public const int LastSyncIdentity = 5;
        }

        protected ConfigurationOperator configurationOperator = new ConfigurationOperator();
        protected string defaultConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configuration.xml");

        /// <summary>
        /// Initializes a new instance of the <see cref="MainWindow"/> class.
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// Handles the Click event of the btn_TestSQL control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btn_TestSQL_Click(object sender, EventArgs e)
        {
            try
            {
                string result = Translator.TestSqlConnection(txt_SqlConn.Text);
                MessageBox.Show(result, "Succeed to connect target server", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Failed to connect target server", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Handles the Load event of the MainWindow control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void MainWindow_Load(object sender, EventArgs e)
        {
            string configurationPath = defaultConfigurationPath;
            if (File.Exists(configurationPath))
            {
                XDocument xDocument = XDocument.Load(configurationPath);
                configurationOperator = new ConfigurationOperator(xDocument);
            }

            RefreshConfigurationDataToForm();
        }

        /// <summary>
        /// Refreshes the configuration data to form.
        /// </summary>
        private void RefreshConfigurationDataToForm()
        {
            txt_MongoConn.Text = configurationOperator.TranslatorSettings.MongoConnectionString.DBToString();
            txt_SqlConn.Text = configurationOperator.TranslatorSettings.SqlConnectionString.DBToString();
            LoadMappingConfiguration(configurationOperator.TranslatorSettings.Mappings);
        }


        /// <summary>
        /// Updates the configuration data from form.
        /// </summary>
        private void UpdateConfigurationDataFromForm()
        {
            configurationOperator.TranslatorSettings.MongoConnectionString = txt_MongoConn.Text;
            configurationOperator.TranslatorSettings.SqlConnectionString = txt_SqlConn.Text;
            configurationOperator.TranslatorSettings.Mappings.Clear();
            configurationOperator.TranslatorSettings.Mappings.AddRange(LoadMappingsFromGrid());
        }

        /// <summary>
        /// Loads the mapping configuration.
        /// </summary>
        /// <param name="mappings">The mappings.</param>
        private void LoadMappingConfiguration(IEnumerable<TableMapping> mappings)
        {
            this.dataGridView_Mapping.Rows.Clear();

            if (mappings != null)
            {
                foreach (var one in mappings)
                {
                    DataGridViewRow row = new DataGridViewRow();
                    row.CreateCells(this.dataGridView_Mapping);

                    row.Cells[ColumnMapping.IsSelected].Value = one.IsSelected;
                    row.Cells[ColumnMapping.SQLTable].Value = one.SQLTable;
                    row.Cells[ColumnMapping.PrimaryKeyColumn].Value = one.PrimaryKeyColumn;
                    row.Cells[ColumnMapping.MongoCollection].Value = one.MongoCollection;
                    row.Cells[ColumnMapping.PageSize].Value = one.PageSize;
                    row.Cells[ColumnMapping.LastSyncIdentity].Value = one.LastSyncIdentity;

                    this.dataGridView_Mapping.Rows.Add(row);
                }
            }
        }

        /// <summary>
        /// Loads the mappings from grid.
        /// </summary>
        /// <returns></returns>
        private List<TableMapping> LoadMappingsFromGrid()
        {
            List<TableMapping> result = new List<TableMapping>();
            foreach (DataGridViewRow row in this.dataGridView_Mapping.Rows)
            {
                TableMapping mapping = new TableMapping();

                mapping.IsSelected = Convert.ToBoolean(row.Cells[ColumnMapping.IsSelected].Value.DBToString());
                mapping.PrimaryKeyColumn = row.Cells[ColumnMapping.PrimaryKeyColumn].Value.DBToString();
                mapping.LastSyncIdentity = row.Cells[ColumnMapping.LastSyncIdentity].Value.DBToString();
                mapping.MongoCollection = row.Cells[ColumnMapping.MongoCollection].Value.DBToString();
                int pageSize;
                int.TryParse(row.Cells[ColumnMapping.PageSize].Value.DBToString(), out pageSize);
                mapping.PageSize = pageSize;
                mapping.SQLTable = row.Cells[ColumnMapping.SQLTable].Value.DBToString();
                result.Add(mapping);
            }

            return result;
        }

        /// <summary>
        /// Handles the Click event of the btn_SaveSettings control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btn_SaveSettings_Click(object sender, EventArgs e)
        {
            UpdateConfigurationDataFromForm();
            configurationOperator.Save(defaultConfigurationPath);
        }

        /// <summary>
        /// Handles the Click event of the btn_TestMongo control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btn_TestMongo_Click(object sender, EventArgs e)
        {
            try
            {
                string result = Translator.TestMongoConnection(txt_MongoConn.Text);
                if (string.IsNullOrEmpty(result))
                {
                    MessageBox.Show("Failed to connect target server", "Failed to connect target server", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    MessageBox.Show(result, "Succeed to connect target server", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Failed to connect target server", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Handles the Click event of the btn_LoadTables control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btn_LoadTables_Click(object sender, EventArgs e)
        {
            try
            {
                List<string> tableNames = Translator.GetTableNames(txt_SqlConn.Text);
                List<TableMapping> mappings = new List<TableMapping>();

                foreach (var one in tableNames)
                {
                    mappings.Add(new TableMapping { SQLTable = one, IsSelected = true, MongoCollection = one });
                }
                LoadMappingConfiguration(mappings);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Failed to get table names", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Handles the Click event of the btn_Start control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btn_Start_Click(object sender, EventArgs e)
        {
            UpdateConfigurationDataFromForm();
            Process.Start(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SqlToMongoCore.exe"), this.configurationOperator.ToXml().ToString().EncodeBase64());
        }

        /// <summary>
        /// Handles the Click event of the btn_SaveSettingsAs control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btn_SaveSettingsAs_Click(object sender, EventArgs e)
        {
            UpdateConfigurationDataFromForm();

            SaveFileDialog fileDialog = new SaveFileDialog();
            fileDialog.AddExtension = true;
            fileDialog.Filter = "Configuration Files | *.xml";
            if (fileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                configurationOperator.Save(fileDialog.FileName);
            }
        }

        /// <summary>
        /// Handles the Click event of the btn_LoadSettings control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btn_LoadSettings_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileDialog = new OpenFileDialog();
            fileDialog.AddExtension = true;
            fileDialog.Filter = "Configuration Files | *.xml";
            if (fileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                try
                {
                    XDocument xDocument = XDocument.Load(fileDialog.FileName);
                    configurationOperator = new ConfigurationOperator(xDocument);
                    RefreshConfigurationDataToForm();
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Failed to load settings. For: " + ex.Message, "Failed to load settings.", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        /// <summary>
        /// Handles the Click event of the btn_SaveCmd control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
        private void btn_SaveCmd_Click(object sender, EventArgs e)
        {
            UpdateConfigurationDataFromForm();

            SaveFileDialog fileDialog = new SaveFileDialog();
            fileDialog.AddExtension = true;
            fileDialog.Filter = "MS-Dos Command Files | *.cmd";
            if (fileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string fileName = fileDialog.FileName.EndsWith(".cmd", StringComparison.InvariantCultureIgnoreCase) ? fileDialog.FileName : fileDialog.FileName + ".cmd";
                string content = string.Format("{0} \"{1}\"", Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SqlToMongoCore.exe"), this.configurationOperator.ToXml().ToString().EncodeBase64());
                File.WriteAllText(fileName, content);

            }
        }
    }
}
